package com.faxsun.core.util.dao;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;

import org.broadleafcommerce.core.order.domain.Order;
import org.broadleafcommerce.core.order.service.type.OrderStatus;
import org.broadleafcommerce.core.util.dao.ResourcePurgeDaoImpl;

import com.faxsun.core.order.domain.FSOrderImpl;
import com.faxsun.core.order.service.type.FSInternalOrderStatus;
import com.faxsun.core.order.service.type.FSOrderStatus;

/**
 * 定时任务Dao,读取待清理的订单：处于支付中（SUBMITTED+PAY_IN_PROCESS）,且超过26个小时未支付
 * @author zhaoteng.song@faxsun.com
 *
 */
public class FSResourcePurgeDaoImpl extends ResourcePurgeDaoImpl implements
		FSResourcePurgeDao {

	/**
	 * 查找待处理订单
	 */
	@Override
	public List<Order> findOrders(String[] names, FSOrderStatus[] statuses,
			FSInternalOrderStatus[] internalStatues,
			Date dateCreatedMinThreshold, Boolean isPreview, int startPos,
			int length) {
		TypedQuery<Order> query = buildOrderQuery(names, statuses,internalStatues,
				dateCreatedMinThreshold, isPreview, Order.class);
		query.setFirstResult(startPos);
		query.setMaxResults(length);
		return query.getResultList();
	}

	/**
	 * 查找待处理订单数目
	 */
	@Override
	public Long findOrdersCount(String[] names, FSOrderStatus[] statuses,
			FSInternalOrderStatus[] internalStatues,
			Date dateCreatedMinThreshold, Boolean isPreview) {
		TypedQuery<Long> query = buildOrderQuery(names, statuses,internalStatues,
				dateCreatedMinThreshold, isPreview, Long.class);
		return query.getSingleResult();
	}

	/**
	 * 待处理订单查询Query
	 * @param names
	 * @param statuses
	 * @param internalStatues
	 * @param dateCreatedMinThreshold
	 * @param isPreview
	 * @param returnType
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected <T> TypedQuery<T> buildOrderQuery(String[] names,
			FSOrderStatus[] statuses, FSInternalOrderStatus[] internalStatues,
			Date dateCreatedMinThreshold, Boolean isPreview, Class<T> returnType) {
		CriteriaBuilder builder = em.getCriteriaBuilder();
		CriteriaQuery<T> criteria = builder.createQuery(returnType);
		Root<FSOrderImpl> root = criteria.from(FSOrderImpl.class);
		if (Long.class.equals(returnType)) {
			criteria.select((Selection<? extends T>) builder.count(root));
		} else {
			criteria.select((Selection<? extends T>) root);
		}
		List<Predicate> restrictions = new ArrayList<Predicate>();
		// 订单状态
		List<String> statusList = new ArrayList<String>();
		if (statuses != null) {
			for (OrderStatus status : statuses) {
				statusList.add(status.getType());
			}
		} else {
			statusList.add("IN_PROCESS");
		}
		restrictions.add(root.get("status").in(statusList));

		// 订单内部状态
		List<String> internalStatusList = new ArrayList<String>();
		if (statuses != null) {
			for (FSInternalOrderStatus status : internalStatues) {
				internalStatusList.add(status.getType());
			}
		} 

		restrictions.add(root.get("internalStatus").in(internalStatusList));

		if (names != null) {
			restrictions.add(root.get("name").in(Arrays.asList(names)));
		}
		if (dateCreatedMinThreshold != null) {
			restrictions.add(builder.lessThan(
					root.get("auditable").get("dateCreated").as(Date.class),
					dateCreatedMinThreshold));
		}
		if (isPreview != null) {
			if (isPreview) {
				restrictions.add(builder.isTrue(root.get("previewable")
						.get("isPreview").as(Boolean.class)));
			} else {
				restrictions
						.add(builder.or(
								builder.isNull(root.get("previewable").get(
										"isPreview")),
								builder.isFalse(root.get("previewable")
										.get("isPreview").as(Boolean.class))));
			}
		}
		criteria.where(restrictions.toArray(new Predicate[restrictions.size()]));
		return em.createQuery(criteria);
	}
}
